/**
 * Title:		SyntaxModifier2.java
 * Description: This program creates several pattern of valid programs from
 * one valid program by mechanically modifying that program. Mofification rules
 * are commented in lines of codes.
 * 
 * @version		1.0 May 2009
 * @author		Kyoho Satsumi (ks2677@columbia.edu)
 *              Murat Dogru   (md2785@columbia.edu)
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SyntaxModifier2 {
	static String readfile;
	static String writefile_prefix;
	
	public static void main(String[] args) throws IOException {
		readfile = args[0];
		int index = readfile.lastIndexOf('.');
		writefile_prefix = readfile.substring(0, index) + "_";
		int caseno = 1;

		String[] slist = new String[4];
	    /** 
	     * substitute one white space to two or more white spaces 
	     * (Case 001)
	     */
		slist[0] = "   ";
		/** 
		 * substitute one white space to two or more tabs (\t) 
		 * (Case 002)
		 */
		slist[1] = "\t\t\t";
		/** 
		 * substitute one white space to two or more line feeds (\f) 
		 * (Case 003)
		 */
		slist[2] = "\f\f\f";
		// substitute all spaces by /* */ comments (Case 004) 
		slist[3] = " /*comments*/";
		
		createFiles(slist, " ", caseno, false);
		caseno = caseno + slist.length;
		
		slist = new String[2];
		/** substitute one tab (\t) to one white space (Case 005) */
		slist[0] = " ";
		/** substitute one tab (\t) to one line feed (\f) (Case 006) */
		slist[1] = "\f";
		
		createFiles(slist, "\t", caseno, false);
		caseno = caseno + slist.length;
		
		slist = new String[3];
		/** add two or more white spaces at the top of each line (Case 007) */
		slist[0] = "\r\n   ";
		/** add two or more tabs at the top of each line (Case 008) */
		slist[1] = "\r\n\t\t\t";
		/** add two or more linefeeds at the top of each line (Case 009) */
		slist[2] = "\r\n\f\f\f";
		
		createFiles(slist, "\r\n", caseno, true);
		caseno = caseno + slist.length;
		
		slist = new String[8];
		/** 
		 * add two or more white spaces at the bottom of 
		 * each line (Case 010) 
		 */
		slist[0] = "   \r\n";
		/** add two or more tabs at the bottom of each line (Case 011) */
		slist[1] = "\t\t\t\r\n";
		/** add two or more linefeeds at the bottom of each line (Case 012) */
		slist[2] = "\f\f\f\r\n";
		/** insert blank line between each line (Case 013) */
		slist[3] = "\r\n\r\n";
		/** insert // comments between each line (Case 014) */
		slist[4] = "\r\n//insert comments between each line\r\n";
		/** add // comments at the bottom of each line (Case 015) */
		slist[5] = "//add comments at the bottom of each line\r\n";
		// insert /* */ comments between each line (Case 016) */
		slist[6] = "\r\n/*insert comments between each line*/\r\n";
		// insert /* comments after each line, insert */ comments 
		// before the next line (Case 017)
		slist[7] = "/* comment start\r\nstill comment\r\ncomment end */";
		
		createFiles(slist, "\r\n", caseno, false);
		caseno = caseno + slist.length;
		
		slist = new String[2];
		/** insert newline before { (Case 018) */
		slist[0] = "\r\n{";
		/** insert newline after { (Case 019) */
		slist[1] = "{\r\n";
		
		createFiles(slist, "\\{", caseno, false);
		caseno = caseno + slist.length;
		
		slist = new String[2];
		/** insert newline before } (Case 020) */
		slist[0] = "\r\n}";
		/** insert newline after } (Case 021) */
		slist[1] = "}\r\n";
		
		createFiles(slist, "\\}", caseno, false);
		caseno = caseno + slist.length;
		
		slist = new String[3];
		/** 
		 * add white spaces before and after each operator, parenthesis, 
		 * comma (Case 022)
		 */
		slist[0] = " ";
		/** 
		 * add tabs before and after each operator, parenthesis, 
		 * comma (Case 023)
		 */
		slist[1] = "\t";
		/** 
		 * add linefeeds before and after each operator, parenthesis, 
		 * comma (Case 024)
		 */
		slist[2] = "\f";
		
		createOperatorFiles(slist, caseno);
		caseno = caseno + slist.length;
		
		/** 
		 * remove all spaces (whitespace, tab, linefeed) at the top of 
		 * each line (Case 025) 
		 */
		removeSpaces(caseno);
		caseno++;
		
		/** remove all blank lines (if existed) (Case 026) */
		removeBlankLines(caseno);
		caseno++;
		
		/** remove newline before { (if existed)  (Case 027) */
	    /** remove newline after {    (if existed)  (Case 028) */
		/** remove newline before }  (if existed)  (Case 029) */
	    /** remove newline after }  (if existed)  (Case 030) */
		removeNewLineCurlyBraces(caseno);
	}
	
	public static void removeNewLineCurlyBraces(int caseno) throws IOException {
		String line;
		String oldcode = "";
		String newcode = "";
		BufferedReader file = new BufferedReader(new FileReader(readfile));
		while((line = file.readLine()) != null) {
			oldcode += line + "\r\n";
		}
		Pattern p = Pattern.compile("\\r\\n(\\s|\\t|\\f|\\r\\n)*\\{");
		Matcher m = p.matcher(oldcode);
		newcode = m.replaceAll("{");		
		String writefile = writefile_prefix + String.format("%03d", caseno) + 
																	".kfrog";
		FileOutputStream out = new FileOutputStream(writefile);
		out.write(newcode.getBytes());
		out.close();
		
		caseno++;
		p = Pattern.compile("\\{(\\s|\\t|\\f|\\r\\n)*\\r\\n");
		m = p.matcher(oldcode);
		newcode = m.replaceAll("{");		
		writefile = writefile_prefix + String.format("%03d", caseno) + ".kfrog";
		out = new FileOutputStream(writefile);
		out.write(newcode.getBytes());
		out.close();
		
		caseno++;
		p = Pattern.compile("\\}(\\s|\\t|\\f|\\r\\n)*\\r\\n");
		m = p.matcher(oldcode);
		newcode = m.replaceAll("}");		
		writefile = writefile_prefix + String.format("%03d", caseno) + ".kfrog";
		out = new FileOutputStream(writefile);
		out.write(newcode.getBytes());
		out.close();
		
		caseno++;
		p = Pattern.compile("\\r\\n(\\s|\\t|\\f|\\r\\n)*\\}");
		m = p.matcher(oldcode);
		newcode = m.replaceAll("}");		
		writefile = writefile_prefix + String.format("%03d", caseno) + ".kfrog";
		out = new FileOutputStream(writefile);
		out.write(newcode.getBytes());
		out.close();
	}
	
	public static void removeSpaces(int caseno) throws IOException {
		String line;
		String code = "";
		BufferedReader file = new BufferedReader(new FileReader(readfile));
		while((line = file.readLine()) != null) {
			code += line + "\r\n";
		}
		Pattern p = Pattern.compile("^(\\s|\\t|\\f)+");
		Matcher m = p.matcher(code);
		code = m.replaceAll("");
		p = Pattern.compile("\\r\\n((\\s|\\t|\\f)+)");
		m = p.matcher(code);
		code = m.replaceAll("\r\n");
		
		String writefile = writefile_prefix + String.format("%03d", caseno) + 
																	".kfrog";
		FileOutputStream out = new FileOutputStream(writefile);
		out.write(code.getBytes());
		out.close();
	}
	
	public static void removeBlankLines(int caseno) throws IOException {
		String line;
		String code = "";
		BufferedReader file = new BufferedReader(new FileReader(readfile));
		while((line = file.readLine()) != null) {
			code += line + "\r\n";
		}
		Pattern p = Pattern.compile("\\r\\n(\\s|\\t|\\f|\\r\\n)*\\r\\n");
		Matcher m = p.matcher(code);
		code = m.replaceAll("\r\n");
		
		String writefile = writefile_prefix + String.format("%03d", caseno) + 
																	".kfrog";
		FileOutputStream out = new FileOutputStream(writefile);
		out.write(code.getBytes());
		out.close();
	}
	
	public static void createFiles(String[] substitutelist, String delimiter, 
								int caseno, boolean front) throws IOException { 
		for (int i = 0; i < substitutelist.length; i++) {
			String writefile = writefile_prefix + 
								String.format("%03d", i + caseno) + ".kfrog";
			FileOutputStream out = new FileOutputStream(writefile);
			if (front) {
				out.write(substitutelist[i].substring(delimiter.length())
																.getBytes());
			}
			Scanner scan = new Scanner(new BufferedReader
										(new FileReader(readfile)))
													.useDelimiter(delimiter);
			while (scan.hasNext()) {
				StringBuffer buffer = new StringBuffer(scan.next());
				if (delimiter.equals("\r\n")) {
					out.write(buffer.append(substitutelist[i]).toString()
																.getBytes());
				} else if (scan.hasNext()) {
					out.write(buffer.append(substitutelist[i]).toString()
																.getBytes());
				} else  {
					out.write(buffer.toString().getBytes());
				}
			}
			out.close();
			scan.close();
		}
	}
	
	public static void createOperatorFiles(String[] addString, int caseno) 
														throws IOException {
		String line;
		String oldcode = "";
		BufferedReader file = new BufferedReader(new FileReader(readfile));
		while((line = file.readLine()) != null) {
			oldcode += line + "\r\n";
		}
		Pattern comment = Pattern.compile("/\\*.*\\*/");
		Matcher mComment = comment.matcher(oldcode);
		oldcode = mComment.replaceAll("");
		comment = Pattern.compile("//.*\\r\\n");
		mComment = comment.matcher(oldcode);
		oldcode = mComment.replaceAll("\r\n");
		
		Pattern operator = 
			Pattern.compile("(\\+=|-=|\\*=|/=|%=|==|>=|<=|NOT=|\\+\\+|" + 
								"--|\\+|-|\\*|/|%|=|>|<|AND|OR|NOT|,|\\(|\\))");	
		Matcher mOperator = operator.matcher(oldcode);
		
		for (int i = 0; i < addString.length; i++) {
			String newcode = "";
			int start = 0;
			String writefile = writefile_prefix + 
								String.format("%03d", i + caseno) + ".kfrog";
			FileOutputStream out = new FileOutputStream(writefile);
			mOperator.reset();
			while(mOperator.find()) {
				newcode += oldcode.substring(start, mOperator.start()) + 
								addString[i] + mOperator.group() + addString[i];
				start = mOperator.end();
			}
			newcode += oldcode.substring(start);
			out.write(newcode.getBytes());
			out.close();
		}
	}
}